﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using DevExpress.Utils;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using System.Collections;

namespace ProgNetComponentsDx.Controls
{
    [ToolboxItem(true)]
    [Designer(typeof(Design.Designers.MultiGroupControlDesigner))]
    public class MultiGroupControl : DevExpress.XtraEditors.XtraPanel
    {
        #region Fields
        private GroupCollapseModes _GroupsCollapseMode;
        private bool _AutoSize = false;
        private Size NoAutoSizeSize;
        internal bool TmpAllowResize
        {
            get;
            set;
        }
        
        private Locations _GroupsLocation;

        private Locations _GroupsCollapseDirection;
        #endregion

        #region Properties
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
        public MultiGroupPanelCollection Groups { get; private set; }

        public Locations GroupsLocation
        {
            get { return _GroupsLocation; }
            set
            {
                if (_GroupsLocation != value)
                {
                    _GroupsLocation = value;
                    foreach (var i in Groups)
                    {
                        if (!i.Collapsed)
                            i.CollapseDirection = value;
                    }
                }
            }
        }

        public Locations GroupsCollapseDirection
        {
            get { return _GroupsCollapseDirection; }
            set
            {
                if (_GroupsCollapseDirection != value)
                {
                    _GroupsCollapseDirection = value;
                    foreach (var i in Groups)
                    {
                        if (i.Collapsed)
                            i.CollapseDirection = value;
                    }
                }
            }
        }

        public GroupCollapseModes GroupsCollapseMode
        {
            get { return _GroupsCollapseMode; }
            set
            {
                _GroupsCollapseMode = value;
                foreach (MultiGroupPanel p in Groups)
                {
                    if (value != GroupCollapseModes.Default)
                        p.CollapseMode = MultiGroupPanel.GroupCollapseModeToCollapseMode(value);
                    else
                        p.OnCollapseModeChanged();
                }
            }
        }

        protected override Size DefaultSize
        {
            get
            {
                return new Size(300, 100);
            }
        }

        public override bool AutoSize
        {
            get
            {
                return _AutoSize;
            }
            set
            {
                if (_AutoSize != value)
                {
                    _AutoSize = value;
                    OnAutoSizeChanged();
                }
            }
        }

        internal MultiGroupPanel FocusedGroup
        {
            get
            {
                return HitTest(PointToClient(Control.MousePosition));
            }
        }

        #endregion

        #region CTOR
        public MultiGroupControl()
        {
            Groups = new MultiGroupPanelCollection(this);
        }
        #endregion

        public void CollapseAll()
        {
            foreach (MultiGroupPanel p in Groups.ToArray())
                p.Collapsed = true;
        }

        public void ExpandAll()
        {
            foreach (MultiGroupPanel p in Groups.ToArray())
                p.Collapsed = false;
        }

        internal DockStyle GetGroupDockStyle()
        {
            switch (GroupsLocation)
            {
                case Locations.Bottom:
                    return DockStyle.Bottom;
                case Locations.Left:
                    return DockStyle.Left;
                case Locations.Right:
                    return DockStyle.Right;
                case Locations.Top:
                case Locations.Default:
                default:
                    return DockStyle.Top;
            }
        }
        
        internal virtual MultiGroupPanel HitTest(Point point)
        {
            Control c = this.GetChildAtPoint(point);
            if (c != null && c is MultiGroupPanel && Groups.Contains((MultiGroupPanel)c))
            {
                return (MultiGroupPanel)c;
            }
            return null;
        }

        protected MultiGroupPanel GetActiveGroup(Control focusedControl)
        {
            if (focusedControl == null)
                return null;
            if (focusedControl is MultiGroupPanel)
            {
                if(this.Controls.Contains(focusedControl))
                    return (MultiGroupPanel)focusedControl;
            }
            return GetActiveGroup(focusedControl.Parent);
        }

        protected override Control.ControlCollection CreateControlsInstance()
        {
            return new MultiGroupControlCollection(this);
        }
        
        protected void OnAutoSizeChanged()
        {
            if (AutoSize)
            {
                NoAutoSizeSize = Size;
                SetAutoSizeSize();
            }
            else
            {
                Size = NoAutoSizeSize;
            }
        }

        internal void SetAutoSizeSize()
        {
            int w = 0;
            int h = 0;
            int minh = this.Height;
            int minw = this.Width;
            bool expandedWidthAdded = false;
            bool expandedHeightAdded = false;

            foreach (MultiGroupPanel p in this.Groups)
            {
                if (!p.Visible)
                    continue;
                
                if (p.Collapsed)
                {
                    if (CollapsiblePanel.IsLeftOrRight(GroupsCollapseDirection))
                    {
                        if (!expandedWidthAdded)
                            w += p.Width;

                    }
                    else
                    {
                        if (!expandedHeightAdded)
                            h += p.Height;
                    }
                }
                else
                {
                    if (CollapsiblePanel.IsLeftOrRight(GroupsLocation))
                    {
                        if (!expandedHeightAdded)
                        {
                            h += p.Height;
                            expandedHeightAdded = true;
                        }
                        w += p.Width;
                    }
                    else
                    {
                        if (!expandedWidthAdded)
                        {
                            w += p.Width;
                            expandedWidthAdded = true;
                        }
                        h += p.Height;
                    }
                }
            }
            if (w == 0)
                w = minw;
            if (h == 0)
                h = minh;
            w += Padding.Left + Padding.Right;
            h += Padding.Top + Padding.Bottom;

            TmpAllowResize = true;
            this.Size = new Size(w, h);
            TmpAllowResize = false;
        }
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            if (AutoSize && !TmpAllowResize)
            {
                width = this.Width;
                height = this.Height;
            }
            base.SetBoundsCore(x, y, width, height, specified);
            foreach (MultiGroupPanel group in Groups)
            {
                if (!group.Collapsed)
                    group.CalcExpandedBounds(false);

            }
        }
    }

    public class MultiGroupControlCollection : Control.ControlCollection
    {
        MultiGroupControl _Owner;
        
        public MultiGroupControlCollection(MultiGroupControl owner)
            : base(owner)
        {
            _Owner = owner;
        }

        public override void Add(Control value)
        {
            MultiGroupPanel page;
            if (!(value is MultiGroupPanel))
                throw new ArgumentException("Only MultiGroupPanel controls can be hosted in this control.");
            page = (MultiGroupPanel)value;
            page.ToogleCollapse += new EventHandler(page_ToogleCollapse);
            base.Add(page);
            var s = page.Size;
            page.SetDocking();
            page.Size = s;
            page.ChildIndex = GetChildIndex(page);
        }

        private MultiGroupPanel GetPage(int idx)
        {
            return this[idx] as MultiGroupPanel;
        }
        private bool lockChildIndex = false;

        public override void SetChildIndex(Control child, int newIndex)
        {
            base.SetChildIndex(child, newIndex);
            if (!lockChildIndex)
            {
                foreach (MultiGroupPanel p in _Owner.Groups.ToArray())
                {
                    p.ChildIndex = GetChildIndex(p);
                }
            }
        }
        /*
         *  this.multiGroupControl1.Controls.Add(this.multiGroupPanel4); 0
            this.multiGroupControl1.Controls.Add(this.multiGroupPanel3); 1
            this.multiGroupControl1.Controls.Add(this.multiGroupPanel2); 2
            this.multiGroupControl1.Controls.Add(this.multiGroupPanel1); 3
         * 
         * 
         *  this.multiGroupControl1.Controls.Add(this.multiGroupPanel4); 0 0
            this.multiGroupControl1.Controls.Add(this.multiGroupPanel3); 1 1
            this.multiGroupControl1.Controls.Add(this.multiGroupPanel1); 2 3
            this.multiGroupControl1.Controls.Add(this.multiGroupPanel2); 3 2
         * */
        private void ShowMsg()
        {
            string str = "";
            var list = _Owner.Groups.ToList();
            list.Sort( (x,y) => { return x.ChildIndex.CompareTo(y.ChildIndex);});
            foreach (var o in list)
            {
                str = str.AppendLine("{0} ChildIndex: {1} GetChildIndex: {2}".FormatMe(o.Name, o.ChildIndex, GetChildIndex(o)));
            }
           // MessageBox.Show(str);
        }
        void page_ToogleCollapse(object sender, EventArgs e)
        {
            MultiGroupPanel page = sender as MultiGroupPanel;
            if (page != null)
            {
                if (CollapsiblePanel.IsLeftOrRight(_Owner.GroupsCollapseDirection) != CollapsiblePanel.IsLeftOrRight(_Owner.GroupsLocation))
                {
                    var otherCollapsed = _Owner.Groups.Where((g) => { return g.Collapsed; });
                    var otherExpanded = _Owner.Groups.Where((g) => { return !g.Collapsed; });
                    List<MultiGroupPanel> otherCollapsedList = null;
                    if (otherCollapsed != null)
                    {
                        otherCollapsedList = otherCollapsed.ToList();
                        otherCollapsedList.Sort((x, y) => { return y.ChildIndex.CompareTo(x.ChildIndex); });
                    }

                    List<MultiGroupPanel> otherExpandedList = null;
                    if (otherExpanded != null)
                    {
                        otherExpandedList = otherExpanded.ToList();
                        otherExpandedList.Sort((x, y) => { return x.ChildIndex.CompareTo(y.ChildIndex); });
                    }

                    ShowMsg();
                    if (page.Collapsed)
                    {
                        int newIdx = Count - 1;
                        if (otherCollapsedList != null)
                            newIdx = Count - 1 - otherCollapsedList.IndexOf(page);
                        
                        lockChildIndex = true;
                        SetChildIndex(page, newIdx);
                        lockChildIndex = false;
                        ShowMsg();
                    }
                    else
                    {
                        int newIdx = 0;
                        if (otherExpandedList != null)
                            newIdx = otherExpandedList.IndexOf(page);
                        
                        lockChildIndex = true;
                        SetChildIndex(page, newIdx);
                        lockChildIndex = false;
                    }
                }
            }
        }

        public override void Remove(Control value)
        {
            base.Remove(value);
        }

        internal IEnumerator BaseEnumerator()
        {
            return base.GetEnumerator();
        }
        public override IEnumerator GetEnumerator()
        {
            return new MultiGroupPanelEnumerator(BaseEnumerator());
        }
        
        public class MultiGroupPanelEnumerator : IEnumerator<MultiGroupPanel>
        {
            IEnumerator baseEnumerator;

            public MultiGroupPanelEnumerator(IEnumerator baseEnumerator)
            {
                this.baseEnumerator = baseEnumerator;
            }

            public MultiGroupPanel Current
            {
                get { return baseEnumerator.Current as MultiGroupPanel; }
            }

            public void Dispose()
            {

            }

            object IEnumerator.Current
            {
                get { return baseEnumerator.Current; }
            }

            public bool MoveNext()
            {
                return baseEnumerator.MoveNext();
            }

            public void Reset()
            {
                baseEnumerator.Reset();
            }
        }
    }
    
    [Designer(typeof(ProgNetComponentsDx.Controls.Design.Designers.MultiGroupPanelDesigner))]
    [ToolboxItem(false)]
    public class MultiGroupPanel : CollapsiblePanel
    {
        public static CollapseModes GroupCollapseModeToCollapseMode(GroupCollapseModes mode)
        {
            switch (mode)
            {
                case GroupCollapseModes.None:
                    return CollapseModes.None;
                case GroupCollapseModes.SingleClick:
                    return CollapseModes.SingleClick;
                case GroupCollapseModes.DoubleClick:
                    return CollapseModes.DoubleClick;
                case GroupCollapseModes.ButtonClick:
                    return CollapseModes.ButtonClick;
                default:
                    return CollapseModes.None;
            }
        }
        [Browsable(false)]
        public int ChildIndex
        {
            get;
            set;
        }

        [RefreshProperties(System.ComponentModel.RefreshProperties.All), 
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Locations CollapseDirection
        {
            get
            {
                if (Owner != null)
                    return Owner.GroupsCollapseDirection;
                return base.CollapseDirection;
            }
            set
            {
                base.CollapseDirection = value;
                SetDocking();
            }
        }
        
        protected override bool ShouldUpdateCollapseDirection()
        {
            return false;
        }

        private MultiGroupControl Owner
        {
            get { return Parent as MultiGroupControl; }
        }
        
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            base.SetBoundsCore(x, y, width, height, specified);
            if (Owner != null && Owner.AutoSize)
                Owner.SetAutoSizeSize();
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            if (Owner != null && Owner.AutoSize)
                Owner.SetAutoSizeSize();
            PreCollapseChanged();
        }
        protected override CollapseModes GetCollapseMode()
        {
            if (Owner != null)
            {
                if (Owner.GroupsCollapseMode != GroupCollapseModes.Default)
                    return GroupCollapseModeToCollapseMode(Owner.GroupsCollapseMode);
            }
            return base.GetCollapseMode();
        }
        protected override void PreCollapseChanged()
        {
            base.PreCollapseChanged();
        }
        protected override void OnCollapseChanged()
        {
            SetDocking();
            base.OnCollapseChanged();
        }
        protected override void SetLocksForCollapsed()
        {
            if (Owner != null)
            {
                LockExpandedSize(false);
                if (IsLeftOrRight(Owner.GroupsLocation))
                    LockExpandedWidth = true;
                else
                    LockExpandedHeight = true;
            }
            else
                base.SetLocksForCollapsed();
        }
        internal void SetDocking()
        {
            if (Owner != null)
            {
                if (Collapsed)
                {
                    this.Dock = GetDockForDirection(Owner.GroupsCollapseDirection);
                }
                else
                {
                    this.Dock = GetDockForDirection(Owner.GroupsLocation);
                }
            }
        }
        
        private DockStyle GetDockForDirection(Locations locations)
        {
            switch (locations)
            {
                case Locations.Bottom:
                    return DockStyle.Bottom;
                case Locations.Default:
                case Locations.Top:
                    return DockStyle.Top;
                case Locations.Left:
                    return DockStyle.Left;
                case Locations.Right:
                    return DockStyle.Right;
                default:
                    return DockStyle.Top;
            }
        }
    }

    public class MultiGroupPanelCollection : IList<MultiGroupPanel>
    {
        private MultiGroupControl Owner;
        #region  Public Constructors

        public MultiGroupPanelCollection(MultiGroupControl owner)
        {
            Owner = owner;
        }

        #endregion  Public Constructors

        public int IndexOf(MultiGroupPanel item)
        {
            return Owner.Controls.IndexOf(item);
        }

        public void Insert(int index, MultiGroupPanel item)
        {
            Owner.Controls.Add(item);
            Owner.Controls.SetChildIndex(item, index);
        }

        public void RemoveAt(int index)
        {
            Owner.Controls.RemoveAt(index);
        }

        public MultiGroupPanel this[int index]
        {
            get
            {
                return Owner.Controls[index] as MultiGroupPanel;
            }
            set
            {
                //throw new NotImplementedException();
            }
        }

        public void Add(MultiGroupPanel item)
        {
            Owner.Controls.Add(item);
            Owner.Controls.SetChildIndex(item, Owner.Controls.Count);
            item.SetDocking();
        }

        public void Clear()
        {
            Owner.Controls.Clear();
        }

        public bool Contains(MultiGroupPanel item)
        {
            return Owner.Controls.Contains(item);
        }

        public void CopyTo(MultiGroupPanel[] array, int arrayIndex)
        {
            Owner.Controls.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return Owner.Controls.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(MultiGroupPanel item)
        {
            Owner.Controls.Remove(item);
            return true;
        }

        public IEnumerator<MultiGroupPanel> GetEnumerator()
        {
            return Owner.Controls.GetEnumerator() as ProgNetComponentsDx.Controls.MultiGroupControlCollection.MultiGroupPanelEnumerator;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Owner.Controls.GetEnumerator();
        }
    }

    public enum GroupCollapseModes
    {
        Default,
        None,
        SingleClick,
        DoubleClick,
        ButtonClick 
    }
}
